#define __PASS__(PTR, TYPE, TBITS, LBITS, HBITS) PTR, TYPE, (TBITS), (LBITS), (HBITS)
#define SWCACHE_INIT(...) SWCACHE_INIT_ASM3(__VA_ARGS__)
#define SWCACHE_TADDR(...) SWCACHE_TADDR_ASM3(__VA_ARGS__)

#define ALN_SIZE(SIZE, TBITS) (((SIZE) + (1 << TBITS) - 1) & ~((1 << TBITS) - 1))
#define SWCACHE_INIT_ASM3(PTR, TYPE, TBITS, LBITS, HBITS)               \
  int PTR ## _access = 0, PTR ## _miss = 0;                             \
  char PTR ## _dat[ALN_SIZE(32 + (8 << HBITS), TBITS) + (1 << TBITS + LBITS + HBITS)]; \
  for (int _i_ = 4; _i_ < (1 << HBITS) + 4; _i_ ++)                     \
    ((long*)PTR ## _dat)[_i_] = -1;                                     \
  dma_desc *PTR ## _dma_desc = PTR ## _dat;                             \
  *PTR ## _dma_desc = 0;                                                \
  dma_set_size(PTR ## _dma_desc, sizeof(TYPE) << LBITS);                \
  dma_set_mode(PTR ## _dma_desc, PE_MODE);                              \
  dma_set_op(PTR ## _dma_desc, DMA_GET);                                \
  dma_set_reply(PTR ## _dma_desc, PTR ## _dat + 16);                    \

#define dma_and_syn(desc, mem, ldm) {                   \
    int t0;                                             \
    asm("vextw %1, 2, %0\n\t"                           \
        "zapnot %0, 3, %0\n\t"                          \
        "stw $31, 0(%0)\n\t"                            \
        "dma %1, %2, %3\n\t"                            \
        "1:\n\t"                                        \
        "vextw %1, 2, %0\n\t"                           \
        "zapnot %0, 3, %0\n\t"                          \
        "ldw %0, 0(%0)\n\t"                             \
        "beq %0, 1b\n\t"                                \
        : "=&r"(t0) : "r"(desc), "r"(mem), "r"(ldm));   \
  }

#ifdef SWCACHE_ENABLE_ASMPROF
#define ASMPROF ""
#else
#define ASMPROF "#"
#endif

#define AMASK(BITS) "((1 << "#BITS") - 1)"
#define AALIGN(SIZE, BITS) "(("SIZE"+"AMASK(BITS)")&~"AMASK(BITS)")"
#define CDATA_OFF(HBITS, TBITS) AALIGN("((8<<"#HBITS") + 32)", TBITS)
#define SWCACHE_TADDR_ASM3(ret, ptr, TYPE, TBITS, LBITS, HBITS, idx) {  \
    int t0, t1, t2, t3;                                                 \
    asm("sll %[IDX], 64 - "#LBITS" - "#HBITS", %[TMP1]\n\t"             \
        "srl %[TMP1], 64 - "#HBITS", %[TMP1]\n\t"                       \
        "s8addl %[TMP1], %[DAT], %[TMP1]\n\t"                           \
        "ldl %[RET], 32(%[TMP1])\n\t"                                   \
        "bic %[IDX], (1 <<"#LBITS") - 1, %[TMP0]\n\t"                   \
        "subl %[RET], %[TMP0], %[RET]\n\t"                              \
        "bne %[RET], 3f\n\t"                                            \
        "bsr $31, 1f\n\t"                                               \
        "3:\n\t"                                                        \
        "stl %[TMP0], 32(%[TMP1])\n\t"                                  \
        ASMPROF"ldw %[TMP1], 28(%[DAT])\n\t"                            \
        "#CTAG and TMP1 can be set free here\n\t"                       \
        "stw $31, 16(%[DAT])\n\t"                                       \
        ASMPROF"ldi %[TMP1], 1(%[TMP1])\n\t"                            \
        ASMPROF"stw %[TMP1], 28(%[DAT])\n\t"                            \
        "vldd %[TMP1], 0(%[DAT])\n\t"                                   \
        "sll %[TMP0], "#TBITS", %[TMP0]\n\t"                            \
        "addl %[TMP0], %[PTR], %[TMP0]\n\t"                             \
        "sll %[IDX], 64 - "#LBITS" - "#HBITS", %[RET]\n\t"              \
        "srl %[RET], 64 - "#HBITS", %[RET]\n\t"                         \
        "sll %[RET], "#TBITS "+" #LBITS ", %[RET]\n\t"                  \
        "addl %[RET], %[DAT], %[RET]\n\t"                               \
        "ldi %[RET], "CDATA_OFF(HBITS, TBITS)"(%[RET])\n\t"             \
        "dma %[TMP1], %[TMP0], %[RET]\n\t"                              \
        "#TMP0 is free now\n\t"                                         \
        "2:\n\t"                                                        \
        "ldw %[TMP0], 16(%[DAT])\n\t"                                   \
        "beq %[TMP0], 2b\n\t"                                           \
        "1:\n\t"                                                        \
        ASMPROF"ldw %[TMP1], 24(%[DAT])\n\t"                            \
        "sll %[IDX], 64 - "#LBITS" - "#HBITS", %[TMP0]\n\t"             \
        "srl %[TMP0], 64 - "#LBITS" - "#HBITS" - "#TBITS", %[TMP0]\n\t" \
        "addl %[DAT], %[TMP0], %[RET]\n\t"                              \
        ASMPROF"ldi %[TMP1], 1(%[TMP1])\n\t"                            \
        ASMPROF"stw %[TMP1], 24(%[DAT])\n\t"                            \
        "ldi %[RET], "CDATA_OFF(HBITS, TBITS)"(%[RET])\n\t"             \
        : [RET]"=r"(ret), [TMP0]"=r"(t1), [TMP1]"=&r"(t2)               \
        : [PTR]"r"(ptr), [IDX]"r"(idx), [DAT]"r"(ptr ## _dat)           \
        );                                                              \
  }

//32491K
#define SWCACHE_TADDR_ASM3_bak(ret, ptr, TYPE, TBITS, LBITS, HBITS, idx) {  \
    int t0, t1, t2, t3;                                                 \
    asm("sll %[IDX], 64 - "#LBITS" - "#HBITS", %[PTAG]\n\t"             \
        "srl %[PTAG], 64 - "#HBITS", %[PTAG]\n\t"                       \
        "s8addl %[PTAG], %[DAT], %[PTAG]\n\t"                           \
        "ldl %[RET], 0(%[PTAG])\n\t"                                    \
        "bic %[IDX], (1 <<"#LBITS") - 1, %[GOFF]\n\t"                   \
        "subl %[RET], %[GOFF], %[RET]\n\t"                              \
        "bne %[RET], 3f\n\t"                                            \
        "bsr $31, 1f\n\t"                                               \
        "3:\n\t"                                                        \
        "stl %[GOFF], 0(%[PTAG])"                                       \
        "#CTAG and PTAG can be set free here\n\t"                       \
        "vextw %[DESC], 2, %[PTAG]\n\t"                                 \
        "stw $31, 0(%[PTAG])\n\t"                                       \
        "sll %[GOFF], "#TBITS", %[GOFF]\n\t"                            \
        "addl %[GOFF], %[PTR], %[GOFF]\n\t"                             \
        "sll %[IDX], 64 - "#LBITS" - "#HBITS", %[RET]\n\t"              \
        "srl %[RET], 64 - "#HBITS", %[RET]\n\t"                         \
        "sll %[RET], "#TBITS "+" #LBITS ", %[RET]\n\t"                  \
        "addl %[RET], %[DAT], %[RET]\n\t"                               \
        "ldi %[RET], 8<<"#HBITS"(%[RET])\n\t"                           \
        "dma %[DESC], %[GOFF], %[RET]\n\t"                              \
        "#GOFF is free now\n\t"                                         \
        "2:\n\t"                                                        \
        "ldw %[GOFF], 0(%[PTAG])\n\t"                                   \
        "beq %[GOFF], 2b\n\t"                                           \
        "1:\n\t"                                                        \
        "sll %[IDX], 64 - "#LBITS" - "#HBITS", %[GOFF]\n\t"             \
        "srl %[GOFF], 64 - "#LBITS" - "#HBITS" - "#TBITS", %[GOFF]\n\t" \
        "addl %[DAT], %[GOFF], %[RET]\n\t"                              \
        "ldi %[RET], 8<<"#HBITS"(%[RET])\n\t"                           \
        : [RET]"=r"(ret), [GOFF]"=r"(t1), [PTAG]"=&r"(t2)               \
        : [PTR]"r"(ptr), [IDX]"r"(idx), [DAT]"r"(ptr ## _dat), [DESC]"r"(ptr ## _dma_desc) \
        );                                                              \
  }

//33453K
#define SWCACHE_TADDR_ASM4(ret, idx, ptr, TYPE, TBITS, LBITS, HBITS) { \
    int t0, t1, t2, t3;                                                 \
    asm("sll %[IDX], 64 - "#LBITS" - "#HBITS", %[PTAG]\n\t"             \
        "srl %[PTAG], 64 - "#HBITS", %[PTAG]\n\t"                       \
        "s8addl %[PTAG], %[TAG], %[PTAG]\n\t"                           \
        "ldl %[RET], 0(%[PTAG])\n\t"                                    \
        "bic %[IDX], (1 <<"#LBITS") - 1, %[GOFF]\n\t"                   \
        "subl %[RET], %[GOFF], %[RET]\n\t"                              \
        "beq %[RET], 1f\n\t"                                            \
        "3:\n\t"                                                        \
        "stl %[GOFF], 0(%[PTAG])"                                       \
        "#CTAG and PTAG can be set free here\n\t"                       \
        "vextw %[DESC], 2, %[PTAG]\n\t"                                 \
        "stl $31, 0(%[PTAG])\n\t"                                       \
        "sll %[GOFF], "#TBITS", %[GOFF]\n\t"                            \
        "addl %[GOFF], %[PTR], %[GOFF]\n\t"                             \
        "sll %[IDX], 64 - "#LBITS" - "#HBITS", %[RET]\n\t"              \
        "srl %[RET], 64 - "#HBITS", %[RET]\n\t"                         \
        "sll %[RET], "#TBITS "+" #LBITS ", %[RET]\n\t"                  \
        "addl %[RET], %[DAT], %[RET]\n\t"                               \
        "dma %[DESC], %[GOFF], %[RET]\n\t"                              \
        "#GOFF is free now\n\t"                                         \
        "2:\n\t"                                                        \
        "ldl %[GOFF], 0(%[PTAG])\n\t"                                   \
        "beq %[GOFF], 2b\n\t"                                           \
        "1:\n\t"                                                        \
        "sll %[IDX], 64 - "#LBITS" - "#HBITS", %[GOFF]\n\t"             \
        "srl %[GOFF], 64 - "#LBITS" - "#HBITS" - "#TBITS", %[GOFF]\n\t" \
        "addl %[DAT], %[GOFF], %[RET]\n\t"                              \
        : [RET]"=r"(ret), [GOFF]"=r"(t1), [PTAG]"=&r"(t2)               \
        : [PTR]"r"(ptr), [IDX]"r"(idx), [TAG]"r"(ptr ## _tag), [DAT]"r"(ptr ## _cache), [DESC]"r"(ptr ## _dma_desc) \
        );                                                              \
  }
